package com.wing.file.service;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.HexUtil;
import com.wing.common.utils.LocalDateTimeUtils;
import com.wing.file.model.response.FileVO;
import com.wing.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang.StringUtils;
import org.apache.tika.Tika;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.UUID;

/**
 * 文件-ServiceImpl
 *
 * @author
 */
@Service
@Slf4j
public class FileServiceImpl implements FileService {

    @Value("${wing.file.app.dir}")
    private String fileDir;
    @Value("${wing.file.app.uuidName}")
    private Boolean uuidName;
    @Value("${wing.file.app.useSm}")
    private Boolean useSm;
    @Value("${wing.file.app.useNginx}")
    private Boolean useNginx;
    @Value("${wing.file.app.nginxUrl}")
    private String nginxUrl;
    @Value("${wing.file.app.tempCleanTime}")
    private Long tempCleanTime;

    private String tempPath = "temp/";

    @Override
    public FileVO saveFile(MultipartFile file) {
        String fileDirPath = fileDir;
        if (fileDirPath == null) {
            fileDirPath = "/";
        }
        if (!fileDirPath.endsWith("/")) {
            fileDirPath += "/";
        }

        // 文件原始名称
        String originalFileName = file.getOriginalFilename();
        String suffix = null;
        String prefix = null;
        if (originalFileName != null) {
            suffix = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
            prefix = originalFileName.substring(0, originalFileName.lastIndexOf("."));
        }
        // 保存到磁盘
        File outFile;
        String path;

        int index = 1;
        path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + originalFileName;
        outFile = new File(File.listRoots()[0], fileDirPath + path);
        while (outFile.exists()) {
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + prefix + "(" + index + ")." + suffix;
            outFile = new File(File.listRoots()[0], fileDirPath + path);
            index++;
        }

        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }
        try {
            file.transferTo(outFile);
        }catch (IOException ex){
            ex.printStackTrace();
            throw new BusinessException("保存文件失败");
        }


        FileVO fileVO = new FileVO();
        fileVO.setUrl(path);

        return fileVO;
    }

    @Override
    public FileVO saveTempImage(MultipartFile file) {

        String fileDirTemp = fileDir;
        if (fileDirTemp == null) {
            fileDirTemp = "/";
        }
        if (!fileDirTemp.endsWith("/")) {
            fileDirTemp += "/";
        }

        fileDirTemp += tempPath;

        // 文件原始名称
        String originalFileName = file.getOriginalFilename();
        String suffix = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
        String prefix = originalFileName.substring(0, originalFileName.lastIndexOf("."));
        // 保存到磁盘
        File outFile;
        String path;
        if (uuidName != null && uuidName) {
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + UUID.randomUUID().toString().replaceAll("-", "") + "." + suffix;
            outFile = new File(File.listRoots()[0], fileDirTemp + path);
        } else {
            int index = 1;
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + originalFileName;
            outFile = new File(File.listRoots()[0], fileDirTemp + path);
            while (outFile.exists()) {
                path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + prefix + "(" + index + ")." + suffix;
                outFile = new File(File.listRoots()[0], fileDirTemp + path);
                index++;
            }
        }

        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }
        try {
            file.transferTo(outFile);
        }catch (IOException ex){
            ex.printStackTrace();
            throw new BusinessException("保存文件失败");
        }


        FileVO fileVO = new FileVO();
        fileVO.setUrl(tempPath + path);

        //生成缩略图
        if (useSm != null && useSm) {
            fileVO.setSmUrl(saveSm(outFile, fileDirTemp, path));
        }

        return fileVO;
    }

    @Override
    public FileVO saveImage(MultipartFile file) {

        String fileDirTemp = fileDir;
        if (fileDirTemp == null) {
            fileDirTemp = "/";
        }
        if (!fileDirTemp.endsWith("/")) {
            fileDirTemp += "/";
        }

        // 文件原始名称
        String originalFileName = file.getOriginalFilename();
        String suffix = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
        String prefix = originalFileName.substring(0, originalFileName.lastIndexOf("."));
        // 保存到磁盘
        File outFile;
        String path;
        if (uuidName != null && uuidName) {
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + UUID.randomUUID().toString().replaceAll("-", "") + "." + suffix;
            outFile = new File(File.listRoots()[0], fileDirTemp + path);
        } else {
            int index = 1;
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + originalFileName;
            outFile = new File(File.listRoots()[0], fileDirTemp + path);
            while (outFile.exists()) {
                path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + prefix + "(" + index + ")." + suffix;
                outFile = new File(File.listRoots()[0], fileDirTemp + path);
                index++;
            }
        }

        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }
        try {
            file.transferTo(outFile);
        }catch (IOException ex){
            ex.printStackTrace();
            throw new BusinessException("保存文件失败");
        }


        FileVO fileVO = new FileVO();
        fileVO.setUrl(tempPath + path);

        //生成缩略图
        if (useSm != null && useSm) {
            fileVO.setSmUrl(saveSm(outFile, fileDirTemp, path));
        }

        return fileVO;
    }

    @Override
    public FileVO saveImage(File file) {

        String fileDirPath = fileDir;
        if (!fileDirPath.endsWith("/")) {
            fileDirPath += "/";
        }

        // 文件原始名称
        String originalFileName = FileUtil.getName(file);
        String suffix = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
        String prefix = originalFileName.substring(0, originalFileName.lastIndexOf("."));
        // 保存到磁盘
        File outFile;
        String path;
        if (uuidName != null && uuidName) {
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + UUID.randomUUID().toString().replaceAll("-", "") + "." + suffix;
            outFile = new File(File.listRoots()[0], fileDirPath + path);
        } else {
            int index = 1;
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + originalFileName;
            outFile = new File(File.listRoots()[0], fileDirPath + path);
            while (outFile.exists()) {
                path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + prefix + "(" + index + ")." + suffix;
                outFile = new File(File.listRoots()[0], fileDirPath + path);
                index++;
            }
        }

        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }

        FileUtil.copyContent(file, outFile, true);

        FileVO fileVO = new FileVO();
        fileVO.setUrl(path);

        //生成缩略图
        if (useSm != null && useSm) {
            fileVO.setSmUrl(saveSm(outFile, fileDirPath, path));
        }


        return fileVO;
    }

    @Override
    public FileVO saveImage(Image image) {

        String fileDirPath = fileDir;
        if (!fileDirPath.endsWith("/")) {
            fileDirPath += "/";
        }

        // 文件原始名称
        String suffix = "jpg";
        // 保存到磁盘
        File outFile;
        String path;
        path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + UUID.randomUUID().toString().replaceAll("-", "") + "." + suffix;
        outFile = new File(File.listRoots()[0], fileDirPath + path);

        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }

        ImgUtil.write(image, outFile);

        FileVO fileVO = new FileVO();
        fileVO.setUrl(path);

        //生成缩略图
        if (useSm != null && useSm) {
            fileVO.setSmUrl(saveSm(outFile, fileDirPath, path));
        }

        return fileVO;
    }

    @Override
    public FileVO saveFile(File file) {

        String fileDirPath = fileDir;
        if (!fileDirPath.endsWith("/")) {
            fileDirPath += "/";
        }

        // 文件原始名称
        String originalFileName = FileUtil.getName(file);
        String suffix = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
        String prefix = originalFileName.substring(0, originalFileName.lastIndexOf("."));
        // 保存到磁盘
        File outFile;
        String path;
        if (uuidName != null && uuidName) {
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + UUID.randomUUID().toString().replaceAll("-", "") + "." + suffix;
            outFile = new File(File.listRoots()[0], fileDirPath + path);
        } else {
            int index = 1;
            path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + originalFileName;
            outFile = new File(File.listRoots()[0], fileDirPath + path);
            while (outFile.exists()) {
                path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + prefix + "(" + index + ")." + suffix;
                outFile = new File(File.listRoots()[0], fileDirPath + path);
                index++;
            }
        }

        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }

        FileUtil.copyContent(file, outFile, true);

        FileVO fileVO = new FileVO();
        fileVO.setUrl(path);

        return fileVO;
    }

    @Override
    public FileVO stringToFile(String content, String suffix) {
        String fileDirTemp = fileDir;
        if (fileDirTemp == null) {
            fileDirTemp = "/";
        }
        if (!fileDirTemp.endsWith("/")) {
            fileDirTemp += "/";
        }

        fileDirTemp += tempPath;
        String path = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyy/MM/dd/") + UUID.randomUUID().toString().replaceAll("-", "") + "." + suffix;
        File file = FileUtil.writeUtf8String(content, fileDirTemp + path);

        return saveFile(file);
    }

    @Override
    public boolean stringToOverrideFile(String path, String content) {
        String fileDirPath = fileDir;
        if (!fileDirPath.endsWith("/")) {
            fileDirPath += "/";
        }
        FileUtil.writeUtf8String(content, fileDirPath + path);
        return true;
    }

    @Override
    public FileVO base64ToImage(String base64) {
        base64 = base64.substring(base64.indexOf(",")+1);
        BufferedImage image = ImgUtil.toImage(base64);
        return saveImage(image);
    }

    @Override
    public boolean base64ToOverrideImage(String path, String base64) {
        base64 = base64.substring(base64.indexOf(",")+1);
        BufferedImage image = ImgUtil.toImage(base64);
        String fileDirPath = fileDir;
        if (!fileDirPath.endsWith("/")) {
            fileDirPath += "/";
        }
        ImgUtil.write(image, new File(fileDirPath + path));
        return true;
    }

    @Override
    public Boolean tempToFile(String tempFilePath) {
        if (tempFilePath == null || tempFilePath.isEmpty() || !tempFilePath.contains(tempPath)) {
            return false;
        }

        String fileDirSave = fileDir;
        if (!fileDirSave.endsWith("/")) {
            fileDirSave += "/";
        }

        File dest = FileUtil.file(getPath(fileDirSave + tempFilePath.replace(tempPath, "")));
        if(dest.exists()){
            return true;
        }

        try {
            //缓存文件移动到正式环境
            File src = FileUtil.file(getPath(fileDirSave + tempFilePath));
            if(!src.exists()){
                return false;
            }
            FileUtil.move(src, dest, true);

            //缓存缩略图文件移动到正式环境
            if (useSm != null && useSm) {

                src = FileUtil.file(getPath(fileDirSave + tempPath + "sm/" + tempFilePath.replace(tempPath, "")));
                if(!src.exists()){
                    return false;
                }

                //文件类型检查
                String type = FileTypeUtil.getType(HexUtil.encodeHexStr(FileUtil.readBytes(src)));
                if(!type.equals("jpg") && !type.equals("png")){
                    return true;
                }

                dest = FileUtil.file( getPath(fileDirSave + "sm/" + tempFilePath.replace(tempPath, "")));
                if(dest.exists()){
                    return true;
                }

                FileUtil.move(src, dest, true);
            }

            //清空缓存
            File[] files = FileUtil.ls(getPath(fileDirSave + tempPath));
            if(files != null && files.length > 0){
                for(int i=0; i<files.length; i++){
                    Date lastDate = FileUtil.lastModifiedTime(files[i]);
                    long betweenSecond = DateUtil.between(lastDate, new Date(), DateUnit.SECOND);
                    if(betweenSecond >= tempCleanTime){
                        FileUtil.del(files[i]);
                    }
                }
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public Boolean delete(String path) {
        if (StringUtils.isEmpty(path)) {
            return false;
        }

        String fileDirSave = fileDir;
        if (!fileDirSave.endsWith("/")) {
            fileDirSave += "/";
        }

        File file = FileUtil.file(getPath(fileDirSave + path));
        if(!file.exists()){
            return true;
        }

        return FileUtil.del(file);
    }

    private String saveSm(File source, String fileDirPath,  String path) {
        // 获取文件类型
        String contentType = null;
        try {
            // contentType = Files.probeContentType(Paths.get(outFile.getName()));
            contentType = new Tika().detect(source);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (contentType != null && contentType.startsWith("image/")) {
            File smImg = new File(File.listRoots()[0], fileDirPath + "sm/" + path);
            if (!smImg.getParentFile().exists()) {
                smImg.getParentFile().mkdirs();
            }
            try {
                Thumbnails.of(source).scale(1f).outputQuality(0.25f).toFile(smImg);
            }catch (IOException ex){
                ex.printStackTrace();
                throw new BusinessException("保存文件失败");
            }

            return "sm/" + path;
        }
        return null;
    }

    private String getPath(String path){
        if(FileUtil.isWindows()){
            path = "C:" + path;
        }
        return path;
    }
}
